package me.tonywang.security.access;

import me.tonywang.common.util.CollectionUtils;
import me.tonywang.common.util.ResourceUtils;
import me.tonywang.common.util.config.Ini;
import me.tonywang.security.util.FilterInvocationSecurityMetadataSourceUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import javax.sql.DataSource;
import java.util.*;


public class ProtectedUrlSecurityMetadataSource implements FilterInvocationSecurityMetadataSource,InitializingBean {

    public static final String URL_SECTION_NAME = "urls";

    public static final String DEFAULT_CONFIG_LOCATION = "security.ini";

    FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Nullable
	private DataSource dataSource;

    @Nullable
	private String configLocation = DEFAULT_CONFIG_LOCATION;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        return securityMetadataSource.getAttributes(object);
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return securityMetadataSource.getAllConfigAttributes();
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return securityMetadataSource.supports(clazz);
    }

    public ProtectedUrlSecurityMetadataSource(Map<String, String> urlMap) {
         this.securityMetadataSource = FilterInvocationSecurityMetadataSourceUtils.createExpressionBasedFilterInvocationSecurityMetadataSource(urlMap);
    }


    public ProtectedUrlSecurityMetadataSource() {

    }


    public ProtectedUrlSecurityMetadataSource(Set<String> urlSet) {
        Map<String, String> urlMap = new LinkedHashMap(urlSet.size());
        for (String resource : urlSet) {
            urlMap.put(resource, resource);
        }
        this.securityMetadataSource = FilterInvocationSecurityMetadataSourceUtils.createExpressionBasedFilterInvocationSecurityMetadataSource(urlMap);
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setConfigLocation(String configLocation) {
        this.configLocation = configLocation;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        reload();
    }

    public synchronized void  reload(){
        Map<String, String> urlMap = new HashMap<>();
        //1.
        if(configLocation!=null ){
            Ini ini = Ini.fromResourcePath(ResourceUtils.CLASSPATH_PREFIX + configLocation);
            //did they explicitly state a 'urls' section?  Not necessary, but just in case:
            Ini.Section section = ini.getSection(URL_SECTION_NAME);
            if (CollectionUtils.isEmpty(section)) {
                //no urls section.  Since this _is_ a urls chain definition property, just assume the
                //default section contains only the definitions:
                section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
            }
            if(!CollectionUtils.isEmpty(section))
                urlMap.putAll(section);
        }
        // 2.
        if(dataSource!=null){

        }
        this.securityMetadataSource = FilterInvocationSecurityMetadataSourceUtils.createExpressionBasedFilterInvocationSecurityMetadataSource(urlMap);
    }
}
